home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / HQX 1.0 / example / hqx.c next >
Encoding:
C/C++ Source or Header  |  1997-07-05  |  15.9 KB  |  613 lines  |  [TEXT/MPS ]

  1.  
  2. /* file hqx.c 
  3.     BinHex decoder/encoder routines, implementation.
  4.     Copyright (c) 1995, 1996, 1997 by John Montbriand.  All Rights Reserved.
  5.     Permission hereby granted for public use.
  6.         Distribute freely in areas where the laws of copyright apply.
  7.     USE AT YOUR OWN RISK.
  8.     DO NOT DISTRIBUTE MODIFIED COPIES.
  9.     Comments/questions/postcards* to the author at the address:
  10.       John Montbriand
  11.       P.O. Box. 1133
  12.       Saskatoon Saskatchewan Canada
  13.       S7K 3N2
  14.     or by email at:
  15.       tinyjohn@sk.sympatico.ca
  16.     *if you mail a postcard, then I will provide you with technical support
  17.     regarding questions you may have about this file.
  18. */
  19.  
  20. #include "hqx.h"
  21. #include <string.h>
  22. #include <Errors.h>
  23. #include <TextUtils.h>
  24. #include <PLStringFuncs.h>
  25. #include <Finder.h>
  26.  
  27.     /* constants */
  28. #define kBinHexMagic 0x1021
  29. #define kRLEFlag 0x90
  30. #define kCopyBufLen 4096
  31. #define HT ((char) 9) /* horizontal tab */
  32. #define LF ((char) 10) /* line feed, newline */
  33. #define CR ((char) 13) /* carriage return */
  34.  
  35.     /* types */
  36. typedef struct {
  37.     unsigned char fInBuffer[4*1024];
  38.     unsigned char fOutBuffer[4*1024];
  39.     unsigned char *fOutBufp;
  40.     long fBitBuffer, fBitBufferBits;
  41.     long fNOutChars;
  42.     long fRLECount;
  43.     unsigned char fRLECharacter;
  44.     unsigned short fCRC;
  45.     HQXSink fSink;
  46.     long fSinkRefCon;
  47. } HQXEncodeVars, *HQXEncVarsPtr;
  48.  
  49. typedef struct {
  50.     unsigned char fInBuffer[4*1024];
  51.     unsigned char fOutBuffer[4*1024];
  52.     unsigned char *fInBufp, *fInBufMax;
  53.     long fBitBuffer, fBitBufferBits;
  54.     long fRLECount;
  55.     unsigned char fRLECharacter;
  56.     Boolean fInHqxData;
  57.     unsigned short fCRC;
  58.     HQXSource fSource;
  59.     long fSourceRefCon;
  60. } HQXDecodeVars, *HQXDecVarsPtr;
  61.  
  62.     /* globals */
  63. static Boolean gHQXinited = false;
  64. static char *gHQX = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
  65. static short hqxtab[256];
  66. static short ihqxtab[256];
  67. static unsigned short crctab[256];
  68.  
  69.  
  70. /* CRC CALCULATION */
  71.  
  72. static void BuildCRCTable(unsigned short magic_number) {
  73.     unsigned long i, magic, mgc, val, bit;
  74.     for (i = 0; i < 256; i++) {
  75.         magic = (magic_number << 8);
  76.         mgc = (magic >> 1);
  77.         val = (i << 16);
  78.         for (bit = 23; bit > 15; bit--) {
  79.             if ((val & (1 << bit)) != 0) val ^= mgc;
  80.             mgc >>= 1;
  81.         }
  82.         crctab[i] = val & 0xFFFF;
  83.     }
  84. }
  85.  
  86. static unsigned short initial_crc(void) {
  87.     return 0;
  88. }
  89.  
  90. static unsigned short crc_byte(unsigned short crc, unsigned char byte) {
  91.     return ( (crctab[(crc >> 8) & 255] ^ ((crc << 8) | byte)) & 0xFFFF );
  92. }
  93.  
  94. static unsigned short crc_run(unsigned short crc, void* buf, long len) {
  95.     unsigned char *ch = buf;
  96.     long i;
  97.     unsigned short crcv = crc;
  98.     for (i = 0; i < len; i++)
  99.          crcv = (crctab[(crcv >> 8) & 255] ^ ((crcv << 8) | (*ch++))) & 0xFFFF;
  100.     return crcv;
  101. }
  102.  
  103. static void HQXInit(void) {
  104.     if (!gHQXinited) {
  105.         long i, n;
  106.         for (i = 0;i < 256;i++) {
  107.             hqxtab[i] = -1;
  108.             ihqxtab[i] = -1;
  109.         }
  110.         for (i = 0, n = strlen(gHQX); i < n; i++) {
  111.             hqxtab[gHQX[i]] = i;
  112.             ihqxtab[i] = gHQX[i];
  113.         }
  114.         hqxtab[CR] = -2;
  115.         hqxtab[LF] = -2;
  116.         hqxtab[HT] = -2;
  117.         hqxtab[' '] = -2;
  118.         hqxtab[':'] = -3;
  119.         BuildCRCTable(kBinHexMagic);
  120.         gHQXinited = true;
  121.     }
  122. }
  123.  
  124.  
  125. /* BUFFERED OUTPUT */
  126.  
  127.  
  128. static OSErr BUFFWrite(HQXEncVarsPtr encv, void* buffer, long count) {
  129.     unsigned char* ch;
  130.     long i;
  131.     OSErr err;
  132.     ch = (unsigned char*) buffer;
  133.     for (i = 0;i < count;i++) {
  134.         if (encv->fOutBufp - encv->fOutBuffer == sizeof(encv->fOutBuffer)) {
  135.             if ((err = encv->fSink(encv->fOutBuffer, sizeof(encv->fOutBuffer), encv->fSinkRefCon)) != noErr) return err;
  136.             encv->fOutBufp = encv->fOutBuffer;
  137.         }
  138.         *encv->fOutBufp++ = *ch++;
  139.     }
  140.     return noErr;
  141. }
  142.  
  143. static OSErr BUFFWriteEnd(HQXEncVarsPtr encv) {
  144.     if (encv->fOutBufp - encv->fOutBuffer > 0)
  145.         return encv->fSink(encv->fOutBuffer, encv->fOutBufp - encv->fOutBuffer, encv->fSinkRefCon);
  146.     else return noErr;
  147. }
  148.  
  149.  
  150. /* HQX OUTPUT */
  151.  
  152. static OSErr HQXWrite(HQXEncVarsPtr encv, void* buffer, long count) {
  153.     unsigned char* ch, code;
  154.     long i, v;
  155.     OSErr err;
  156.     ch = (unsigned char*) buffer;
  157.     for (i = 0; i < count; i++, ch++) {
  158.         encv->fBitBuffer = (encv->fBitBuffer << 8) | ((*ch)&255);
  159.         encv->fBitBufferBits += 8;
  160.         while (encv->fBitBufferBits >= 6) {
  161.             v = (encv->fBitBuffer >> (encv->fBitBufferBits-6)) & 0x003F;
  162.             encv->fBitBufferBits -= 6;
  163.             code = ihqxtab[v];
  164.             if ((err = BUFFWrite(encv, &code, 1)) != noErr) return err;
  165.             encv->fNOutChars++;
  166.             if ((encv->fNOutChars % 64) == 0) {
  167.                 if ((err = BUFFWrite(encv, "\n", 1)) != noErr) return err;
  168.             }
  169.         }
  170.     }
  171.     return noErr;
  172. }
  173.  
  174. static OSErr HQXWriteEnd(HQXEncVarsPtr encv) {
  175.     unsigned char code;
  176.     OSErr err;
  177.     if (encv->fBitBufferBits > 0) {
  178.         code = ihqxtab[encv->fBitBuffer<<(6-encv->fBitBufferBits) & 0x03F];
  179.         if ((err = BUFFWrite(encv, &code, 1)) != noErr) return err;
  180.         encv->fNOutChars++;
  181.     }
  182.     return BUFFWrite(encv, ":\n", 2);
  183. }
  184.  
  185.  
  186. /* RLE OUTPUT */
  187.  
  188.  
  189. static OSErr FlushRLE(HQXEncVarsPtr encv) {
  190.     long n;
  191.     OSErr err;
  192.     unsigned char buffer[10], *putp;
  193.     while (encv->fRLECount > 0) {
  194.         n = encv->fRLECount > 255 ? 255 : encv->fRLECount;
  195.         putp = buffer;
  196.         *putp++ = encv->fRLECharacter;
  197.         if (encv->fRLECharacter == kRLEFlag) {
  198.             *putp++ = 0;    /* literal flag value */
  199.             if (n == 2) {
  200.                 *putp++ = kRLEFlag;
  201.                 *putp++ = 0;    /* literal flag value */
  202.             } else if (n > 2) {
  203.                 *putp++ = kRLEFlag;
  204.                 *putp++ = n;    /* repeat count */
  205.             }
  206.         } else {
  207.             if (n == 2)
  208.                 *putp++ = encv->fRLECharacter;
  209.             else if (n == 3) {
  210.                 *putp++ = encv->fRLECharacter;
  211.                 *putp++ = encv->fRLECharacter;
  212.             } else if (n > 3) {
  213.                 *putp++ = kRLEFlag;
  214.                 *putp++ = n;
  215.             }
  216.         }
  217.         if ((err = HQXWrite(encv, buffer, putp - buffer)) != noErr) return err;
  218.         encv->fRLECount -= n;
  219.     }
  220.     return err;
  221. }
  222.  
  223. static OSErr RLEWrite(HQXEncVarsPtr encv, void* buffer, long count) {
  224.     unsigned char *ch;
  225.     long i;
  226.     OSErr err;
  227.     ch = (unsigned char*) buffer;
  228.     err = noErr;
  229.     for (ch = (unsigned char*) buffer, i = 0; i < count; i++, ch++) {
  230.         if (encv->fRLECount == 0) {
  231.             encv->fRLECharacter = *ch;
  232.             encv->fRLECount = 1;
  233.         } else if (*ch == encv->fRLECharacter)
  234.             encv->fRLECount += 1;
  235.         else {
  236.             if ((err = FlushRLE(encv)) != noErr) return err;
  237.             encv->fRLECharacter = *ch;
  238.             encv->fRLECount = 1;
  239.         }
  240.     }
  241.     return err;
  242. }
  243.  
  244. static OSErr RLEWriteEnd(HQXEncVarsPtr encv) {
  245.     OSErr err;
  246.     if ((err = FlushRLE(encv)) != noErr) return err;
  247.     if ((err = HQXWriteEnd(encv)) != noErr) return err;
  248.     return BUFFWriteEnd(encv);
  249. }
  250.  
  251.  
  252. static OSErr WriterInit(HQXEncVarsPtr encv, HQXSink dst, long refcon) {
  253.     OSErr err;
  254.     char *p;
  255.     p = "(This file must be converted with BinHex 4.0)\n:";
  256.     encv->fRLECount = 0;
  257.     encv->fOutBufp = encv->fOutBuffer;
  258.     encv->fSink = dst;
  259.     encv->fSinkRefCon = refcon;
  260.     if ((err = BUFFWrite(encv, p, strlen(p))) != noErr) return err;
  261.     encv->fNOutChars = 1;
  262.     encv->fBitBuffer = encv->fBitBufferBits = 0;
  263.     return noErr;
  264. }
  265.  
  266. /* CRC OUTPUT */
  267.  
  268.  
  269. static OSErr CRCWriteInit(HQXEncVarsPtr encv) {
  270.     encv->fCRC = initial_crc();
  271.     return noErr;
  272. }
  273.  
  274. static OSErr CRCWrite(HQXEncVarsPtr encv, void* buffer, long count) {
  275.     encv->fCRC = crc_run(encv->fCRC, buffer, count);
  276.     return RLEWrite(encv, buffer, count);
  277. }
  278.  
  279. static OSErr CRCWriteEnd(HQXEncVarsPtr encv) {
  280.     encv->fCRC = crc_byte(encv->fCRC, 0);
  281.     encv->fCRC = crc_byte(encv->fCRC, 0);
  282.     return RLEWrite(encv, &encv->fCRC, 2);
  283. }
  284.  
  285.  
  286. OSErr HQXEncode(StringPtr name, short vol, long dir, HQXSink dst, long refcon) {
  287.     OSErr err;
  288.     long zero, bytecount, actcount;
  289.     short refnum;
  290.     HParamBlockRec pb;
  291.     HQXEncVarsPtr encv;
  292.     
  293.         /* set up */
  294.     zero = 0;
  295.     refnum = 0;
  296.     encv = NULL;
  297.     HQXInit();
  298.     encv = (HQXEncVarsPtr) NewPtrClear(sizeof(HQXEncodeVars));
  299.     if ((err = MemError()) != noErr) goto bail;
  300.     encv->fRLECount = 0;
  301.     
  302.     err = WriterInit(encv, dst, refcon);
  303.     if (err != noErr) goto bail;
  304.  
  305.         /* hqx file header */
  306.     err = CRCWriteInit(encv);
  307.     if (err != noErr) goto bail;
  308.         memset(&pb, 0, sizeof(pb));
  309.         pb.fileParam.ioNamePtr = name;
  310.         pb.fileParam.ioDirID = dir;
  311.         pb.fileParam.ioVRefNum = vol;
  312.         pb.fileParam.ioFDirIndex = 0;
  313.         pb.fileParam.ioFVersNum = 0;
  314.         err = PBHGetFInfoSync(&pb);
  315.         if (err != noErr) goto bail;
  316.         err = CRCWrite(encv, name, *name + 1);
  317.         if (err != noErr) goto bail;
  318.         err = CRCWrite(encv, &zero, 1);
  319.         if (err != noErr) goto bail;
  320.         err = CRCWrite(encv, &pb.fileParam.ioFlFndrInfo, 10);
  321.         if (err != noErr) goto bail;
  322.         err = CRCWrite(encv, &pb.fileParam.ioFlLgLen, 4);
  323.         if (err != noErr) goto bail;
  324.         err = CRCWrite(encv, &pb.fileParam.ioFlRLgLen, 4);
  325.         if (err != noErr) goto bail;
  326.     err = CRCWriteEnd(encv);
  327.     if (err != noErr) goto bail;
  328.  
  329.         /*  file data fork */
  330.     err = CRCWriteInit(encv);
  331.     if (err != noErr) goto bail;
  332.         err = HOpenDF(vol, dir, name, fsRdPerm, &refnum);
  333.         if (err != noErr) goto bail;
  334.         for (bytecount = 0; bytecount < pb.fileParam.ioFlLgLen; bytecount += actcount) {
  335.             actcount = pb.fileParam.ioFlLgLen - bytecount;
  336.             if (actcount > sizeof(encv->fInBuffer)) actcount = sizeof(encv->fInBuffer);
  337.             err = FSRead(refnum, &actcount, encv->fInBuffer);
  338.             if (err != noErr) goto bail;
  339.             err = CRCWrite(encv, encv->fInBuffer, actcount);
  340.             if (err != noErr) goto bail;
  341.         }
  342.         FSClose(refnum); refnum = 0;
  343.     err = CRCWriteEnd(encv);
  344.     if (err != noErr) goto bail;
  345.  
  346.         /* file resource fork */
  347.     err = CRCWriteInit(encv);
  348.     if (err != noErr) goto bail;
  349.         err = HOpenRF(vol, dir, name, fsRdPerm, &refnum);
  350.         if (err != noErr) goto bail;
  351.         for (bytecount = 0; bytecount < pb.fileParam.ioFlRLgLen; bytecount += actcount) {
  352.             actcount = pb.fileParam.ioFlRLgLen - bytecount;
  353.             if (actcount > sizeof(encv->fInBuffer)) actcount = sizeof(encv->fInBuffer);
  354.             err = FSRead(refnum, &actcount, encv->fInBuffer);
  355.             if (err != noErr) goto bail;
  356.             err = CRCWrite(encv, encv->fInBuffer, actcount);
  357.             if (err != noErr) goto bail;
  358.         }
  359.         FSClose(refnum); refnum = 0;
  360.     err = CRCWriteEnd(encv);
  361.     if (err != noErr) goto bail;
  362.     
  363.     err = RLEWriteEnd(encv);
  364.     if (err != noErr) goto bail;
  365.     DisposePtr((Ptr) encv);
  366.     
  367.     return noErr;
  368.     
  369. bail:
  370.     if (refnum != 0) FSClose(refnum);
  371.     if (encv != NULL) DisposePtr((Ptr) encv);
  372.     return err;
  373. }
  374.     
  375.  
  376.  
  377.  
  378. /* BINHEX DECODER */
  379.  
  380.  
  381. /* HQX INPUT, HQXSource calls */
  382.  
  383. static OSErr GetNextCharacter(HQXDecVarsPtr decv, unsigned char* the_char) {
  384.     OSErr err;
  385.     long bytes;
  386.     if (decv->fInBufp >= decv->fInBufMax) {
  387.         err = decv->fSource(decv->fInBuffer, (bytes = sizeof(decv->fInBuffer), &bytes), decv->fSourceRefCon);
  388.         if (err == eofErr) err = noErr;
  389.         if (err != noErr) return err;
  390.         decv->fInBufp = decv->fInBuffer;
  391.         decv->fInBufMax = decv->fInBuffer + bytes;
  392.         if (decv->fInBufp >= decv->fInBufMax) return eofErr;
  393.     }
  394.     *the_char = *decv->fInBufp++;
  395.     return noErr;
  396. }
  397.  
  398. static OSErr HQXRead(HQXDecVarsPtr decv, void* buffer, long count) {
  399.     unsigned char *dst, code;
  400.     long i;
  401.     long readcode;
  402.     OSErr err;
  403.  
  404.     dst = (unsigned char*) buffer;
  405.     for ( i = 0; i < count; i++) {
  406.         while (decv->fBitBufferBits < 8)  {
  407.             readcode = -1;
  408.             while (readcode < 0) {
  409.                     /* get the next character */
  410.                 err = GetNextCharacter(decv, &code);
  411.                 if (err != noErr) return err;
  412.                     /* look up the code in the table and dispatch on the value */
  413.                 readcode = hqxtab[code];
  414.                 if (readcode == -3) {
  415.                     decv->fInHqxData = !decv->fInHqxData;
  416.                 } else if (!decv->fInHqxData)
  417.                     readcode = -1;
  418.             }            
  419.             decv->fBitBuffer = (decv->fBitBuffer<<6) | readcode;
  420.             decv->fBitBufferBits += 6;
  421.         }
  422.         *dst++ = (decv->fBitBuffer>>(decv->fBitBufferBits-8));
  423.         decv->fBitBufferBits -= 8;
  424.     }
  425.     
  426.     return noErr;
  427. }
  428.  
  429.  
  430. /* RLE INPUT,  HQXRead calls */
  431.  
  432. static OSErr RLERead(HQXDecVarsPtr decv, void* buffer, long count) {
  433.     unsigned char *ch, nextchar, countvalue;
  434.     long i;
  435.     OSErr err;
  436.  
  437.     ch = (unsigned char*) buffer;
  438.     err = noErr;
  439.     for ( i=0; i < count; )
  440.         if (decv->fRLECount > 0) {
  441.             *ch++ = decv->fRLECharacter;
  442.             decv->fRLECount--;
  443.             i++;
  444.         } else {
  445.             if ((err = HQXRead(decv, &nextchar, 1)) != noErr) return err;
  446.             if (nextchar == kRLEFlag) {
  447.                 if ((err = HQXRead(decv, &countvalue, 1)) != noErr) return err;
  448.                 if (countvalue == 0) {
  449.                     decv->fRLECharacter = kRLEFlag;
  450.                     decv->fRLECount = 1;
  451.                 } else decv->fRLECount = countvalue - 1;
  452.             } else {
  453.                 decv->fRLECharacter = nextchar;
  454.                 decv->fRLECount = 1;
  455.             }
  456.         }
  457.         
  458.     return noErr;
  459. }
  460.  
  461.  
  462. /* CRC INPUT, RLERead calls */
  463.  
  464. static OSErr CRCReadInit(HQXDecVarsPtr decv) {
  465.     decv->fCRC = initial_crc();
  466.     return noErr;
  467. }
  468.  
  469. static OSErr CRCRead(HQXDecVarsPtr decv, void* buffer, long count) {
  470.     OSErr err;
  471.     if ((err = RLERead(decv, buffer, count)) != noErr) return err;
  472.     decv->fCRC = crc_run(decv->fCRC, buffer, count);
  473.     return noErr;
  474. }
  475.  
  476. static OSErr CRCReadEnd(HQXDecVarsPtr decv) {
  477.     OSErr err;
  478.     unsigned short saved_crc;
  479.     if ((err = RLERead(decv, &saved_crc, 2)) != noErr) return err;
  480.     decv->fCRC = crc_byte(decv->fCRC, 0);
  481.     decv->fCRC = crc_byte(decv->fCRC, 0);
  482.     if (saved_crc != decv->fCRC) return paramErr; else return noErr;
  483. }
  484.  
  485.  
  486.  
  487. /* FILE INPUT, CRCRead calls */
  488.  
  489. OSErr HQXDecode(HQXSource src, HQXNameFilter fname, Boolean can_replace, Boolean header_search, long refcon) {
  490.     OSErr err;
  491.     FInfo info, tinfo;
  492.     long zero, bytecount, actcount, dir, data_length, rsrc_length;
  493.     short refnum, vol;
  494.     Str255 name;
  495.     Boolean file_exists;
  496.     HQXDecVarsPtr decv;
  497.     
  498.         /* set up */
  499.     HQXInit();
  500.     decv = NULL;
  501.     zero = 0;
  502.     refnum = 0;
  503.     vol = 0;
  504.     dir = 0;
  505.     file_exists = false;
  506.         
  507.         /* allocate shared variables */
  508.     decv = (HQXDecVarsPtr) NewPtrClear(sizeof(HQXDecodeVars));
  509.     if ((err = MemError()) != noErr) goto bail;
  510.  
  511.         /* reader globals */
  512.     decv->fRLECount = 0;
  513.     decv->fInBufMax = decv->fInBufp = decv->fInBuffer;
  514.     decv->fSource = src;
  515.     decv->fSourceRefCon = refcon;
  516.     decv->fBitBuffer = decv->fBitBufferBits = 0;
  517.     decv->fInHqxData = false;
  518.     
  519.         /* search for the header string */
  520.     if (header_search) {
  521.         char *header, *headerp, inputchar;
  522.         headerp = header = "(This file must be converted with BinHex 4.0)";
  523.         while (*headerp != '\0') {
  524.             err = GetNextCharacter(decv, (unsigned char*) &inputchar);
  525.             if (err != noErr) goto bail;
  526.             if (inputchar == *headerp) headerp++; else headerp = header;
  527.         }
  528.     }
  529.     
  530.         /* hqx file header */
  531.     err = CRCReadInit(decv);
  532.     if (err != noErr) goto bail;
  533.     err = CRCRead(decv, name, 1);
  534.     if (err != noErr) goto bail;
  535.     err = CRCRead(decv, name+1, *name);
  536.     if (err != noErr) goto bail;
  537.     err = CRCRead(decv, &zero, 1);
  538.     if (err != noErr) goto bail;
  539.     err = CRCRead(decv, &info, 10);
  540.     if (err != noErr) goto bail;
  541.     err = CRCRead(decv, &data_length, 4);
  542.     if (err != noErr) goto bail;
  543.     err = CRCRead(decv, &rsrc_length, 4);
  544.     if (err != noErr) goto bail;
  545.     err = CRCReadEnd(decv);
  546.     if (err != noErr) goto bail;
  547.     
  548.           /* create destination file */
  549.     if (fname != NULL) {
  550.         err = fname(name, &vol, &dir, refcon);
  551.         if (err != noErr) goto bail;
  552.     }
  553.     if (can_replace) {
  554.         err = HDelete(vol, dir, name);
  555.         if (err == fnfErr) err = noErr;
  556.         if (err != noErr) goto bail;
  557.     }
  558.     err = HCreate(vol, dir, name, info.fdCreator, info.fdType);
  559.     if (err != noErr) goto bail;
  560.     file_exists = true;
  561.     err = HGetFInfo(vol, dir, name, &tinfo);
  562.     if (err != noErr) goto bail;
  563.     tinfo.fdFlags = info.fdFlags & (~kHasBeenInited);
  564.     err = HSetFInfo(vol, dir, name, &tinfo);
  565.     if (err != noErr) goto bail;
  566.  
  567.         /* file data fork */
  568.     err = CRCReadInit(decv);
  569.     if (err != noErr) goto bail;
  570.     err = HOpenDF(vol, dir, name, fsRdWrPerm, &refnum);
  571.     if (err != noErr) goto bail;
  572.     for (bytecount = 0; bytecount < data_length; bytecount += actcount) {
  573.         actcount = data_length - bytecount;
  574.         if (actcount > sizeof(decv->fOutBuffer)) actcount = sizeof(decv->fOutBuffer);
  575.         err = CRCRead(decv, decv->fOutBuffer, actcount);
  576.         if (err != noErr) goto bail;
  577.         err = FSWrite(refnum, &actcount, decv->fOutBuffer);
  578.         if (err != noErr) goto bail;
  579.     }
  580.     FSClose(refnum); refnum = 0;
  581.     err = CRCReadEnd(decv);
  582.     if (err != noErr) goto bail;
  583.  
  584.         /* file resource fork */
  585.     err = CRCReadInit(decv);
  586.     if (err != noErr) goto bail;
  587.     err = HOpenRF(vol, dir, name, fsRdWrPerm, &refnum);
  588.     if (err != noErr) goto bail;
  589.     for (bytecount = 0; bytecount < rsrc_length; bytecount += actcount) {
  590.         actcount = rsrc_length - bytecount;
  591.         if (actcount > sizeof(decv->fOutBuffer)) actcount = sizeof(decv->fOutBuffer);
  592.         err = CRCRead(decv, decv->fOutBuffer, actcount);
  593.         if (err != noErr) goto bail;
  594.         err = FSWrite(refnum, &actcount, decv->fOutBuffer);
  595.         if (err != noErr) goto bail;
  596.     }
  597.     FSClose(refnum); refnum = 0;
  598.     err = CRCReadEnd(decv);
  599.     if (err != noErr) goto bail;
  600.  
  601.     DisposePtr((Ptr) decv);
  602.     return noErr;
  603.     
  604. bail:
  605.     if (refnum != 0) FSClose(refnum);
  606.     if (file_exists) HDelete(vol, dir, name);
  607.     if (decv != NULL) DisposePtr((Ptr) decv);
  608.     return err;
  609. }
  610.  
  611.  
  612. /* end of file hqx.c */
  613.